using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Security.Principal;
using System.Windows.Input;
using Microsoft.Practices.Prism.Commands;

namespace TrackMe.Apps.VM
{
	[Export]
	public class WidgetVM : BasicViewModel<IWidgetView>
	{
		public IUserForList CurrentUser { get; set; }
		public IStatMatrix Matrix { get; set; }
		[Export("SelectTask")]
		public ICommand SelectTaskCmd;
		[Export("EditorTask")]
		public ICommand EditorTaskCmd;
		#pragma warning disable 0649
		[Import]
		private IDatabase database;
        [Import]
        private IDialogService dialogService;
        [Import]
        private CompositionContainer container;
		[Import] 
		private TfsSyncControl tfsSync;
		#pragma warning restore 0649

		public string Description { get; set; }

	    public ICommand StartCmd { get; private set; }
        public ICommand StopCmd { get; private set; }
        public ICommand ReportsCmd { get; private set;}
        private ITaskForSelect currentTask;
		public ITaskForSelect CurrentTask
		{
			get { return currentTask; }
			set
			{
				if (currentTask != value)
				{
					currentTask = value;
					RaisePropertyChanged(() => CurrentTask);
				}
			}
		}

		private IJob currentJob;
		public IJob CurrentJob
		{
			get { return currentJob; }
			set
			{
				if (currentJob != value)
				{
					currentJob = value;
					jobStartedAt = DateTime.Now;
					ReloadMatrix();
					RaisePropertyChanged(() => CurrentJob);
				}
			}
		}


		private object selectedTab;
		public object SelectedTab
		{
			get { return selectedTab; }
			set
			{
				if (selectedTab != value)
				{
					var vm = ViewCore.GetChildVM(value) as IActivatable;
					if (vm != null)
						vm.OnActivate();
					selectedTab = value;
				}
			}
		}

		internal DateTime MatrixUpdateTime;
		private DateTime jobStartedAt;

		[ImportingConstructor]
		public WidgetVM(IWidgetView view): base(view)
		{
			Matrix = AutoIntf.New<IStatMatrix>();
			SelectTaskCmd = new DelegateCommand<ITaskForSelect>(OnSelectTask, CanSelectTask);
		    
            ReportsCmd = new DelegateCommand<object>(ShowReport);
		    
            StartCmd = new DelegateCommand<object>(
		        p => StartTask(),
		        p => (CurrentTask != null) && CurrentJob == null)
		        .ListenOn(this, n => n.CurrentTask, null)
		        .ListenOn(this, n => n.CurrentJob, null);

            EditorTaskCmd = new DelegateCommand<object>(
		        p => EditorTask(),
		        p => (CurrentTask != null) && CurrentJob == null)
		        .ListenOn(this, n => n.CurrentTask, null)
		        .ListenOn(this, n => n.CurrentJob, null);

            StopCmd = new DelegateCommand<object>(
                p => StopTask(), 
                p => CurrentJob != null)
		        .ListenOn(this, n => n.CurrentJob, null);
		}

		private void EditorTask()
		{
			throw new NotImplementedException();
		}

		private void ShowReport(object o)
	    {
            var vm = container.GetExportedValue<ReportVM>();
            //vm.Model = AutoIntf.New<IReport>();
	        dialogService.PopupDialog(vm);
        }

	    private static bool CanSelectTask(ITaskForSelect arg)
		{
			return true;
		}

		private void OnSelectTask(ITaskForSelect task)
		{
			if (CurrentJob != null)
			{
				StopTask();
			}

			CurrentTask = task;
			StartTask();
			RaisePropertyChanged(() => CurrentTask);

		}

		private void Load()
		{
			WindowsIdentity winUser = WindowsIdentity.GetCurrent();
		    if (winUser != null) 
                database.Login(winUser.Name, winUser.User.Value);

		    CurrentTask = database.RecentTasks(1).FirstOrDefault();
			ReloadMatrix();
		}

		private void ReloadMatrix()
		{
			AutoIntf.Copy(Matrix, database.LoadStats(CurrentTask == null ? 0: CurrentTask.TaskId));
			MatrixUpdateTime = DateTime.Now;
		}

		public void UpdateMatrix()
		{
			if (CurrentJob != null)
			{
				var delta = DateTime.Now - MatrixUpdateTime;
				MatrixUpdateTime = DateTime.Now;
				Matrix.MonthProject += delta;
				Matrix.MonthTask += delta;
				Matrix.MonthTotal += delta;
				Matrix.TodayProject += delta;
				Matrix.TodayTask += delta;
				Matrix.TodayTotal += delta;

				Matrix.TotalProject += delta;
				Matrix.TotalTask += delta;
				Matrix.TotalTotal += delta;
			}
		}

		private void StartTask()
		{
			CurrentJob = database.StartTask(currentTask.TaskId, Description);
			ReloadMatrix();
		}

		public void ContinueOrphanJob(IJob job)
		{
			CurrentJob = job;
		}
        
		public void StopTask()
		{
			database.StopTask(CurrentJob.Id);
			CurrentJob = null;
			UpdateProgressInTfs();
			tfsSync.Heartbeat(true);
		}

		private void UpdateProgressInTfs()
		{
		    foreach(var clockout in database.PendingClockOuts())
                tfsSync.UpdateProgress(clockout.ExternalId, clockout.Time, clockout.JobId, clockout.ServerId);
        }

		public void Show()
		{
			Load();
			ViewCore.Show();
		}

		public void AddChild(CreateVM createVM)
		{
			ViewCore.SetCreateView(createVM.View);
		}

	    public void AddChild(TaskSearchVM searchVM)
	    {
            ViewCore.SetSearchView(searchVM.View);
        }

	    public void AddChild(RecentTaskVM recentVM)
	    {
            ViewCore.SetRecentView(recentVM.View);
        }

		public void HeartBeat()
		{
			UpdateMatrix();
			CheckInactivity();
			tfsSync.Heartbeat(false);
		}

		private void CheckInactivity()
		{
			TimeSpan inactive = (DateTime.Now - DeviceListener.LastActivity());
			if (currentJob != null && inactive.TotalSeconds > 300)
			{
				var stillWorking = dialogService.ShowYesNoQuestion(string.Format(
					"You have been inactive for {0}. \n Are you still working on the task \n{1}?", inactive, currentTask.TaskName));

				double totalHours = (DateTime.Now - jobStartedAt).TotalHours;
				if (!stillWorking && totalHours > 8)
					stillWorking = dialogService.ShowYesNoQuestion(string.Format(
						"You are working {0} hours in a row. \n Are you sure you are still working on the task \n{1}?", totalHours, currentTask.TaskName));
				if (!stillWorking)
					StopTask();
			}
		}
	}
}

